Source Code / C / Self Replicating Code - Games++News | Forums | Play 
      Online | Submit Article | Submit BETA | Advertise | Contact | Keyword 
      Query 


       
                   
                   
                  The C Answer Book 2nd Edition. 


                   
                   
                  C For Dummies, Volume One & Two Bundle 


                   
                   
                  Absolute Beginner's Guide to C (2nd Edition) 

                  Self Replicating Code
                  A recent posting of a generator for self-extracting compressed 
                  program reminded me of the self-replicating program I posted a 
                  year or two back (after one of the inevitable rounds of 
                  discussion about same). Since I'd played around a bit more 
                  with it, I decided to dust it off and fix it up a bit. 
                  There are actually three separate versions of programs here. 
                  The interesting part is that it is a fairly general shell for 
                  building self-replicating programs. Obviously, the job can be 
                  done much more easily if the only goal is to write a program 
                  that can re-create it's source. 
                  Instructions for use: snip and copy to a file, compile it, 
                  create a new directory and cd to it, then run the program. 
e.g.
cc -o replicate replicate.c
mkdir self
cd self
../replicate
This will create a makefile and several source files. The file 
                  "selfcopy.c" in the new directory should be the same as what 
                  I'm posting. "make test" will build and test all three 
                  versions. 
                  The three programs are: 
                    self just reproduces its source on stdout 
                    selfshar reproduces on stdout a shar file that contains the 
                    sources for re-creating a new version of itself (requires 
                    "shar") 
                    replicate creates the source tree for building itself and 
                    the other two programs (in the current directory); also 
                    creates a file selfcopy.c, which should be identical to 
                    replicate.c 
                  Sorry for the lack of comments. 
                  Here is replicate.c: 
char	*selfish[] = {
"#include \n",
"\n",
"void\tdup(p, out)\n",
"\tchar\t*p[];\n",
"\tFILE\t*out;\n",
"{\n",
"\tchar\t*c;\n",
"\n",
"\twhile (c = *p++)\n",
"\t\tfputs(c, out);\n",
"}\n",
"\n",
"void\tmakehead(aname, out)\n",
"\tchar\t*aname;\n",
"\tFILE\t*out;\n",
"{\n",
"\tfprintf(out, \"char\\t*%s[] = {\\n\", aname);\n",
"}\n",
"\n",
"void\tmakeline(c, out)\n",
"\tchar\t*c;\n",
"\tFILE\t*out;\n",
"{\n",
"\tchar\tch;\n",
"\n",
"\tputc('\"', out);\n",
"\twhile (ch = *c++) {\n",
"\t\tif ((ch == '\"') || (ch == '\\\\') || (ch == '\\n') ||\n",
"\t\t\t(ch == '\\t'))\n",
"\t\t\tputc('\\\\', out);\n",
"\t\tif (ch == '\\n')\n",
"\t\t\tputc('n', out);\n",
"\t\telse if (ch == '\\t')\n",
"\t\t\tputc('t', out);\n",
"\t\telse\n",
"\t\t\tputc(ch, out);\n",
"\t}\n",
"\tfputs(\"\\\",\\n\", out);\n",
"}\n",
"\n",
"void\tmaketail(out)\n",
"\tFILE\t*out;\n",
"{\n",
"\tfputs(\"0};\\n\\n\", out);\n",
"}\n",
"\n",
"void\tclone(aname, p, out)\n",
"\tchar\t*aname;\n",
"\tchar\t*p[];\n",
"\tFILE\t*out;\n",
"{\n",
"\tmakehead(aname, out);\n",
"\twhile (*p)\n",
"\t\tmakeline(*p++, out);\n",
"\tmaketail(out);\n",
"}\n",
"\n",
"void\tclonehead(aname, out)\n",
"\tchar\t*aname;\n",
"\tFILE\t*out;\n",
"{\n",
"\tfprintf(out, \"\\nstruct self {\\n\");\n",
"\tfprintf(out, \"\\tchar\\t**txt;\\n\");\n",
"\tfprintf(out, \"\\tchar\\t*name;\\n\");\n",
"\tfprintf(out, \"\\tchar\\t*file;\\n\");\n",
"\tfprintf(out, \"} %s[] = {\\n\", aname);\n",
"}\n",
"\n",
"void\tcloneline(aname, afile, out)\n",
"\tchar\t*aname;\n",
"\tchar\t*afile;\n",
"\tFILE\t*out;\n",
"{\n",
"\tfprintf(out, \"\\t%s, \\\"%s\\\", \\\"%s\\\",\\n\", aname, aname, afil",
"e);\n",
"}\n",
"\n",
"void\tclonetail(aname, afile, out)\n",
"\tchar\t*aname;\n",
"\tchar\t*afile;\n",
"\tFILE\t*out;\n",
"{\n",
"\tfprintf(out, \"\\t0, \\\"%s\\\", \\\"%s\\\"\\n\", aname, afile);\n",
"\tfprintf(out, \"};\\n\\n\");\n",
"}\n",
0};

char	*replicate[] = {
"void\tcloneself(last, out)\n",
"\tstruct self\t*last;\n",
"\tFILE\t*out;\n",
"{\n",
"\tstruct self\t*p;\n",
"\n",
"\tclonehead(last->name, out);\n",
"\tfor (p = self; p->txt; p++)\n",
"\t\tcloneline(p->name, p->file, out);\n",
"\tclonetail(last->name, last->file, out);\n",
"}\n",
"\n",
"void\tdupself(out)\n",
"{\n",
"\tstruct self\t*p;\n",
"\n",
"\tfor (p = self; p->txt; p++)\n",
"\t\tclone(p->name, p->txt, out);\n",
"\tcloneself(p, out);\n",
"\tdup(self[0].txt, out);\n",
"\tdup(self[1].txt, out);\n",
"}\n",
"\n",
"void\tdupfile(p)\n",
"\tstruct self\t*p;\n",
"{\n",
"\tFILE\t*out;\n",
"\n",
"\tif (!(out = fopen(p->file, \"w\"))) {\n",
"\t\tfprintf(stderr, \"dupfile: create \");\n",
"\t\tperror(p->file);\n",
"\t\texit(1);\n",
"\t}\n",
"\tif (p->txt)\n",
"\t\tdup(p->txt, out);\n",
"\telse\n",
"\t\tdupself(out);\n",
"\tfclose(out);\n",
"}\n",
"\n",
"void\tdupfiles()\n",
"{\n",
"\tstruct self\t*p;\n",
"\n",
"\tfor (p = self; p->txt; p++)\n",
"\t\tdupfile(p);\n",
"\tdupfile(p);\n",
"}\n",
"\n",
"int\tmain(argc, argv)\n",
"\tint\targc;\n",
"\tchar\t*argv[];\n",
"{\n",
"\tdupfiles();\n",
"\treturn 0;\n",
"}\n",
0};

char	*replicant[] = {
"\n",
"int\tmain()\n",
"{\n",
"\tclone(\"self\", self, stdout);\n",
"\tclone(\"replicant\", replicant, stdout);\n",
"\tdup(self, stdout);\n",
"\tdup(replicant, stdout);\n",
"}\n",
0};

char	*shar[] = {
"#include \n",
"\n",
"int\tmain()\n",
"{\n",
"\tchar\t**p;\n",
"\tchar\t*s;\n",
"\n",
"\tp = shar;\n",
"\twhile (s = *p++)\n",
"\t\tfputs(s, stdout);\n",
"\treturn 0;\n",
"}\n",
0};

char	*make[] = {
"all:\tself selfshar replicate\n",
"\n",
"test:\tall\n",
"\trm -rf cmp\n",
"\tmkdir cmp\n",
"\t./self > cmp/self.c\n",
"\tcmp self.c cmp/self.c\n",
"\trm -f cmp/*\n",
"\t./selfshar > cmp/shar\n",
"\tcd cmp; unshar shar; make selfshar; ./selfshar > shar\n",
"\tcmp cmp/shar cmp/self.shar\n",
"\trm -f cmp/*\n",
"\tcd cmp; ../replicate\n",
"\tcmp replicate.c cmp/selfcopy.c\n",
"\tcd cmp; make replicate.c\n",
"\tcmp replicate.c cmp/replicate.c\n",
"\trm -rf cmp\n",
"\n",
"self:\tself.c\n",
"\tcc -o self self.c\n",
"\n",
"self.c:\tmakeself replicant.self\n",
"\t./makeself self selfish.c replicant replicant.self - selfi",
"sh.c replicant.self > self.c\n",
"\n",
"selfshar:\tselfshar.c\n",
"\tcc -o selfshar selfshar.c\n",
"\n",
"selfshar.c:\tmakeself self.shar\n",
"\t./makeself shar self.shar - selfshar.self > selfshar.c\n",
"\n",
"self.shar:\tselfish.c clone.c makeself.c selfshar.self Makef",
"ile\n",
"\tshar selfish.c clone.c makeself.c selfshar.self Makefile >",
" self.shar\n",
"\n",
"replicate:\treplicate.c\n",
"\tcc -o replicate replicate.c\n",
"\n",
"replicate.c:\tmakeself replicate.self replicant.self selfsha",
"r.self Makefile\n",
"\t./makeself selfish selfish.c replicate replicate.self repl",
"icant replicant.self shar selfshar.self make Makefile build",
" makeself.c cloner clone.c -self selfcopy.c selfish.c repli",
"cate.self > replicate.c\n",
"\n",
"makeself:\tmakeself.o selfish.o clone.o\n",
"\tcc -o makeself makeself.o selfish.o clone.o\n",
"\n",
"clean:\n",
"\trm -f replicate.c self.c selfshar.c replicate self selfsha",
"r self.shar copy.c\n",
"\n",
"realclean:\tclean\n",
"\trm -f *.o makeself\n",
"\trm -rf cmp\n",
0};

char	*build[] = {
"#include \n",
"\n",
"int\tmain(argc, argv)\n",
"\tint\targc;\n",
"\tchar\t*argv[];\n",
"{\n",
"\tint\tindex;\n",
"\tint\tclonal;\n",
"\n",
"\tclonal = 0;\n",
"\tfor (index = 1; index < argc; index += 2) {\n",
"\t\tif (*argv[index] == '-') {\n",
"\t\t\tclonal = index;\n",
"\t\t\tbreak;\n",
"\t\t}\n",
"\t\tmakeself(argv[index], argv[index+1], stdout);\n",
"\t}\n",
"\tif (clonal) {\n",
"\t\tif (argv[clonal][1]) {\n",
"\t\t\tclonehead(argv[clonal]+1, stdout);\n",
"\t\t\tfor (index = 1; index < clonal; index += 2)\n",
"\t\t\t\tcloneline(argv[index], argv[index+1], stdout);\n",
"\t\t\tclonetail(argv[clonal]+1, argv[clonal+1], stdout);\n",
"\t\t\tclonal += 1;\n",
"\t\t}\n",
"\t\tfor (index = clonal + 1; index < argc; index += 1)\n",
"\t\t\tcopyfile(argv[index], stdout);\n",
"\t}\n",
"\treturn 0;\n",
"}\n",
0};

char	*cloner[] = {
"#include \n",
"\n",
"#define\tMAXLINE\t60\n",
"\n",
"void\tmakeself(aname, fname, out)\n",
"\tchar\t*aname;\n",
"\tchar\t*fname;\n",
"\tFILE\t*out;\n",
"{\n",
"\tFILE\t*in;\n",
"\tchar\tp[MAXLINE];\n",
"\n",
"\tif (!(in = fopen(fname, \"r\"))) {\n",
"\t\tfprintf(stderr, \"makeself: create \");\n",
"\t\tperror(fname);\n",
"\t\texit(1);\n",
"\t}\n",
"\tmakehead(aname, out);\n",
"\twhile (fgets(p, MAXLINE, in))\n",
"\t\tmakeline(p, out);\n",
"\tmaketail(out);\n",
"\tfclose(in);\n",
"}\n",
"\n",
"void\tcopyfile(fname, out)\n",
"\tchar\t*fname;\n",
"\tFILE\t*out;\n",
"{\n",
"\tFILE\t*in;\n",
"\tchar\ts[MAXLINE];\n",
"\n",
"\tif (!(in = fopen(fname, \"r\"))) {\n",
"\t\tfprintf(stderr, \"copyfile: open \");\n",
"\t\tperror(fname);\n",
"\t\texit(1);\n",
"\t}\n",
"\twhile (fgets(s, MAXLINE, in))\n",
"\t\tfputs(s, out);\n",
"\tfclose(in);\n",
"}\n",
0};


struct self {
	char	**txt;
	char	*name;
	char	*file;
} self[] = {
	selfish, "selfish", "selfish.c",
	replicate, "replicate", "replicate.self",
	replicant, "replicant", "replicant.self",
	shar, "shar", "selfshar.self",
	make, "make", "Makefile",
	build, "build", "makeself.c",
	cloner, "cloner", "clone.c",
	0, "self", "selfcopy.c"
};

#include 

void	dup(p, out)
	char	*p[];
	FILE	*out;
{
	char	*c;

	while (c = *p++)
		fputs(c, out);
}

void	makehead(aname, out)
	char	*aname;
	FILE	*out;
{
	fprintf(out, "char\t*%s[] = {\n", aname);
}

void	makeline(c, out)
	char	*c;
	FILE	*out;
{
	char	ch;

	putc('"', out);
	while (ch = *c++) {
		if ((ch == '"') || (ch == '\\') || (ch == '\n') ||
			(ch == '\t'))
			putc('\\', out);
		if (ch == '\n')
			putc('n', out);
		else if (ch == '\t')
			putc('t', out);
		else
			putc(ch, out);
	}
	fputs("\",\n", out);
}

void	maketail(out)
	FILE	*out;
{
	fputs("0};\n\n", out);
}

void	clone(aname, p, out)
	char	*aname;
	char	*p[];
	FILE	*out;
{
	makehead(aname, out);
	while (*p)
		makeline(*p++, out);
	maketail(out);
}

void	clonehead(aname, out)
	char	*aname;
	FILE	*out;
{
	fprintf(out, "\nstruct self {\n");
	fprintf(out, "\tchar\t**txt;\n");
	fprintf(out, "\tchar\t*name;\n");
	fprintf(out, "\tchar\t*file;\n");
	fprintf(out, "} %s[] = {\n", aname);
}

void	cloneline(aname, afile, out)
	char	*aname;
	char	*afile;
	FILE	*out;
{
	fprintf(out, "\t%s, \"%s\", \"%s\",\n", aname, aname, afile);
}

void	clonetail(aname, afile, out)
	char	*aname;
	char	*afile;
	FILE	*out;
{
	fprintf(out, "\t0, \"%s\", \"%s\"\n", aname, afile);
	fprintf(out, "};\n\n");
}
void	cloneself(last, out)
	struct self	*last;
	FILE	*out;
{
	struct self	*p;

	clonehead(last->name, out);
	for (p = self; p->txt; p++)
		cloneline(p->name, p->file, out);
	clonetail(last->name, last->file, out);
}

void	dupself(out)
{
	struct self	*p;

	for (p = self; p->txt; p++)
		clone(p->name, p->txt, out);
	cloneself(p, out);
	dup(self[0].txt, out);
	dup(self[1].txt, out);
}

void	dupfile(p)
	struct self	*p;
{
	FILE	*out;

	if (!(out = fopen(p->file, "w"))) {
		fprintf(stderr, "dupfile: create ");
		perror(p->file);
		exit(1);
	}
	if (p->txt)
		dup(p->txt, out);
	else
		dupself(out);
	fclose(out);
}

void	dupfiles()
{
	struct self	*p;

	for (p = self; p->txt; p++)
		dupfile(p);
	dupfile(p);
}

int	main(argc, argv)
	int	argc;
	char	*argv[];
{
	dupfiles();
	return 0;
}






      Discuss this Article in the Forums 


